package net.qhzw.vip.qiyu.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import lombok.extern.slf4j.Slf4j;
import net.qhzw.vip.qiyu.config.ApiConfig;
import net.qhzw.vip.qiyu.config.WxProperties;
import net.qhzw.vip.qiyu.dto.PayInfoDto;
import net.qhzw.vip.qiyu.entity.Order;
import net.qhzw.vip.qiyu.entity.OrderSettlement;
import net.qhzw.vip.qiyu.enums.PayType;
import net.qhzw.vip.qiyu.handler.ApiException;
import net.qhzw.vip.qiyu.mapper.OrderMapper;
import net.qhzw.vip.qiyu.mapper.OrderRefundsMapper;
import net.qhzw.vip.qiyu.mapper.OrderSettlementMapper;
import net.qhzw.vip.qiyu.param.PayParam;
import net.qhzw.vip.qiyu.service.PayService;
import net.qhzw.vip.qiyu.util.Arith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PayServiceImpl implements PayService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderSettlementMapper orderSettlementMapper;

    @Autowired
    private OrderRefundsMapper orderRefundsMapper;


    @Autowired
    private ApplicationEventPublisher eventPublisher;

//    @Autowired
//    private Snowflake snowflake;

//    @Autowired
//    private WxPayService wxMiniPayService;

    @Autowired
    private ApiConfig apiConfig;

    @Autowired
    private WxProperties properties;

    @Value("${spring.profiles.active}")
    private String active;

    /**
     * 不同的订单号，同一个支付流水号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayInfoDto pay(Long userId, PayParam payParam) {
        // 不同的订单号的产品名称
        StringBuilder prodName = new StringBuilder();
        // 支付单号
        String payNo = String.valueOf(IdWorker.getId());
        String[] orderNumbers = payParam.getOrderNumbers().split(StrUtil.COMMA);
        // 修改订单信息
        for (String orderNumber : orderNumbers) {
            OrderSettlement orderSettlement = new OrderSettlement();
            orderSettlement.setPayNo(payNo);
            orderSettlement.setPayType(payParam.getPayType());
            orderSettlement.setUserId(userId);
            orderSettlement.setOrderNumber(orderNumber);
            orderSettlementMapper.updateByOrderNumberAndUserId(orderSettlement);
        }
        Order order = orderMapper.getOrderByOrderNumber(orderNumbers[0]);
        prodName.append(order.getProdName()).append("等商品");
        // 除了ordernumber不一样，其他都一样
        List<OrderSettlement> settlements = orderSettlementMapper.getSettlementsByPayNo(payNo);
        // 应支付的总金额
        double payAmount = 0.0;
        for (OrderSettlement orderSettlement : settlements) {
            payAmount = Arith.add(payAmount, orderSettlement.getPayAmount());
        }
        if (active.equals("dev") || "test".equals(active)) {
            payAmount = 0.01;
        }
        prodName.substring(0, Math.min(100, prodName.length() - 1));
        PayInfoDto payInfoDto = new PayInfoDto();
        payInfoDto.setBody(prodName.toString());
        payInfoDto.setPayAmount(payAmount);
        payInfoDto.setPayNo(payNo);
        return payInfoDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> paySuccess(String payNo, String bizPayNo) {
        List<OrderSettlement> orderSettlements = orderSettlementMapper.selectList(new LambdaQueryWrapper<OrderSettlement>()
                .eq(OrderSettlement::getPayNo, payNo));
        OrderSettlement settlement = orderSettlements.get(0);
        // 订单已支付
        if (settlement.getPayStatus() == 1) {
            throw new ApiException("订单已支付");
        }
        // 修改订单结算信息
        if (orderSettlementMapper.updateToPay(payNo, settlement.getVersion()) < 1) {
            throw new ApiException("结算信息已更改");
        }
        List<String> orderNumbers = orderSettlements.stream().map(OrderSettlement::getOrderNumber).collect(Collectors.toList());
        // 将订单改为已支付状态
        orderMapper.updateByToPaySuccess(orderNumbers, PayType.WECHATPAY.value());
        List<Order> orders = orderNumbers.stream().map(orderNumber -> orderMapper.getOrderByOrderNumber(orderNumber)).collect(Collectors.toList());
        //eventPublisher.publishEvent(new PaySuccessOrderEvent(orders));
        orderSettlementMapper.updateSettlementsByPayNo(payNo, bizPayNo);
        return orderNumbers;
    }

    @Override
    public WxPayRefundResult refund(Long userId, PayParam payParam) {
        log.info("【退款】：{}", payParam, userId);
        WxPayRefundResult wxPayRefundResult = null;
        try {
            WxPayRefundRequest refundRequest = new WxPayRefundRequest();
            PayInfoDto payInfo = refundPay(userId, payParam.getOrderNumbers());
            String refundNo = IdWorker.getId() + ""; //退款单号
            refundRequest.setOutRefundNo(refundNo);
            //String transactionId = orderSettlementMapper.getSettlementsPayNoByOrderNumber(payParam.getOrderNumbers());
            //refundRequest.setOutTradeNo("");
            refundRequest.setTransactionId(payInfo.getPayNo());
            refundRequest.setTotalFee((int) Arith.mul(payInfo.getPayAmount(), 100)); //金额
            refundRequest.setRefundFee((int) Arith.mul(payInfo.getPayAmount(), 100)); //退款金额
            refundRequest.setNotifyUrl(apiConfig.getDomainName() + "/mall/notice/pay/refund");
            refundRequest.setRefundDesc("商品退款");

            WxPayConfig payConfig = new WxPayConfig();
            payConfig.setAppId(properties.getAppId());
            payConfig.setMchId(properties.getMchId());
            payConfig.setMchKey(properties.getMchKey());
            payConfig.setKeyPath(properties.getKeyPath());
            payConfig.setSignType(WxPayConstants.SignType.MD5);
            payConfig.setTradeType("JSAPI");
            payConfig.setSignType("MD5");
            WxPayService wxPayService = new WxPayServiceImpl();
            wxPayService.setConfig(payConfig);
            wxPayRefundResult = wxPayService.refund(refundRequest);

            orderRefundsMapper.updatereFundNo(refundNo, payParam.getOrderNumbers());
            return wxPayRefundResult;
        } catch (Exception e) {

            throw new ApiException(e.getMessage());
        }
    }

    private PayInfoDto refundPay(Long userId, String orderNumber) {
        PayInfoDto payInfoDto = orderMapper.refundPay(userId, orderNumber);
        return payInfoDto;
    }

}
